package palindrome;

import java.util.ArrayList;
import java.util.List;

/**
 * Class that realized logic of finding palindromes in a string.
 *
 * @author Muzalevskiy Vitaliy
 */
public class Palindrome {
    /**
     * <code> String </code> type value of string in which palindromes will be
     * found.
     */
    private String value;
    
    /**
     * Value of inputed string transform to array of symbols. 
     */
    private String[] symbolArray;
    
    /**
     * Constructor of <code> Palindrome </code> class that get string as argument
     * and transform it into symbols array.
     *
     * @param value <code> String </code> type value of string in which 
     *      palindromes will be found.
     */
    public Palindrome(String value) {
        this.value = value;
        symbolArray = new String[value.length()];
        for (int i = 0; i < value.length(); i++) {
            symbolArray[i] = value.substring(i, i + 1);
        }
    }

    /**
     * This method return all palindromes founded in inputed string.
     *
     * @return <code> ArrayList </code> of founded palindromes.
     */
    public List<String> getPalindroms() {
        List<String> result = new ArrayList<String>(){
        @Override
        public String toString(){
            StringBuilder result = new StringBuilder("Results:\n");
            for(int i = 0; i < this.size(); i++){
                result.append(i + 1).append(".").append(this.get(i)).append('\n');
            }
            return result.toString();            
        }};
        result.addAll(getUnpairedPalindromeList());
        result.addAll(getPairedPalindromeList());
        return result;
    }

    /**
     * Method return all unpaired palindromes from inputed string.
     * 
     * @return <code> ArrayList </code> of founded palindromes.
     */
    private List<String> getUnpairedPalindromeList() {
        int unpairedLengthStep = 1;
        List<String> result = new ArrayList<String>();
        for (int i = 1; i < symbolArray.length - 1; i++) {
            if (symbolArray[i - 1].equals(symbolArray[i + 1])) {
                result.add(value.substring(i - 1,i + 1 + 1));
                result.addAll(getElsePalindromeList(i, unpairedLengthStep,
                        unpairedLengthStep));
            }
        }
        return result;
    }

    /**
     * Method return all paired palindromes from inputed string.
     * 
     * @return <code> ArrayList </code> of founded palindromes.
     */
    private List<String> getPairedPalindromeList() {
        int pairedLengthStep = 1;
        List<String> result = new ArrayList<String>();
        for (int i = 0; i < (symbolArray.length - 1); i++) {
            if (symbolArray[i].equals(symbolArray[i + 1])) {
                result.addAll(getElsePalindromeList(i, pairedLengthStep,
                        pairedLengthStep - 1));
            }
        }
        return result;
    }

    /**
     * That method return all palindromes length of which is more than 3 and 
     * they have the same root.
     * 
     * @param rootNumber central symbol of palindrome.
     * @param leftStep step to left from root symbol that limits current
     *      palindrome.
     * @param rightStep step to right from root symbol that limits current
     *      palindrome.
     * @return <code> ArrayList </code> of founded palindromes.
     */
    private List<String> getElsePalindromeList(int rootNumber,
            int leftStep, int rightStep) {
        List<String> result = new ArrayList<String>();
        while (leftStep <= (symbolArray.length / 2)) {
            leftStep++;
            rightStep++;
            int resultListSize = result.size();
            if ((rootNumber >= rightStep)
                    && (rootNumber < (symbolArray.length - leftStep))
                    && (symbolArray[rootNumber - rightStep]
                    .equals(symbolArray[rootNumber + leftStep]))) {
                result.add(value.substring(rootNumber - rightStep,
                        rootNumber + leftStep + 1));
            }
            if (result.size() == resultListSize) {
                break;
            }
        }
        return result;
    }
}